﻿using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using CommunityToolkit.Mvvm.Messaging;
using CommunityToolkit.Mvvm.Messaging.Messages;
using Daq.Devices;
using Daq.Models;
using Daq.ViewModels;
using Daq.Views;
using Microsoft.Extensions.DependencyInjection;
using Serilog;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading;
using System.Threading.Tasks;
using Telerik.Windows.Controls;
using Telerik.Windows.Controls.Charting;
using Telerik.Windows.Media.Imaging.Commands;
using Telerik.Windows.Persistence.Core;

namespace Daq.Services
{
    public partial class DeviceService : ObservableRecipient//, IRecipient<ValueChangedMessage<ChartTimeDivision>>
    {
        public async Task<List<DeviceInfo>?> Search()
        {
            return await DxDaq.SearchDevices();
        }


        public ObservableCollection<DaqBase> Daqs { get; set; } = [];
        [ObservableProperty]
        private ObservableCollection<DaqInfo> devices = [];

        [ObservableProperty]
        private DaqBase? daq;
        public List<DeviceInfo>? DeviceInfos { get; set; }
        private DaqBase? CreateDaqDevice(DeviceInfo info)
        {
            return CreateDaqDevice(info.Model, info.SN);
        }

        [ObservableProperty]
        private ObservableCollection<DaqChannelInfo>? channels;

        private static Dictionary<string, DaqBase> deviceDictionary = new();

        public DaqBase? CreateDaqDevice(string? model, string? sn)
        {
            if (string.IsNullOrWhiteSpace(model)) return null;
            if (string.IsNullOrWhiteSpace(sn)) return null;

            if(deviceDictionary.TryGetValue(sn, out var device))
            {
                return device;
            }
            DaqBase? daq = null;
            switch (model)
            {
                case "DX2100":
                    daq = (App.Current.Services.GetService<DaqBase>()) as DX2100;
                    if(daq != null)
                    {
                        deviceDictionary.Add(sn, daq);
                    }
                    break;
                case "DX2204":
                    daq = new DX2204(sn);
                    deviceDictionary.Add(sn, daq);
                    break;
            }
            return daq;
        }

        private Dictionary<string, bool> chartVisibilityDictionary = new();

        public void SetChartVisibility(string name, bool visible)
        {
            if (chartVisibilityDictionary.ContainsKey(name))
            {
                chartVisibilityDictionary[name] = visible;
            }
            else
            {
                chartVisibilityDictionary.Add(name, visible);
            }
        }

        public async Task OpenDevices(List<DeviceInfo>? devices = null)
        {
            if (devices != null)
            {
                DeviceInfos = devices;
            }

            if (DeviceInfos == null) return;

            Daqs ??= [];
            Devices = [];
            int index = 1;
            foreach (var info in DeviceInfos)
            {
                var dev = CreateDaqDevice(info);
                if (dev == null) continue;
                await dev.OpenAsync(info.Address, CancellationToken.None);
                //await dev.GetChannelsAsync(CancellationToken.None);
                
                //Daqs.Add(dev);
                var daqInfo = await dev.GetDaqInfo(CancellationToken.None);
                
                if(daqInfo != null)
                {
                    daqInfo.Address = info.Address;
                    if (settings.DaqsSettings.Instance.Daqs != null)
                    {
                        var daqInfoSettings = settings.DaqsSettings.Instance.Daqs.FirstOrDefault(daq => daq.SN == daqInfo.SN);
                        if(daqInfoSettings != null)
                        {
                            if(daqInfoSettings.Channels != null && daqInfo.Channels != null && daqInfoSettings.Channels.Count == daqInfo.Channels.Count)
                            {
                                for(int i = 0; i < daqInfo.Channels.Count; i++)
                                {
                                    var daqInfoChannel = daqInfo.Channels[i];
                                    var daqInfoSettingsChannel = daqInfoSettings.Channels[i];
                                    daqInfoChannel.Status = daqInfoSettingsChannel.Status;
                                    if(!daqInfoChannel.IsEnabled)
                                    {
                                        daqInfoChannel.Status = false;
                                    }
                                    daqInfoChannel.Unit = daqInfoSettingsChannel.Unit;
                                    daqInfoChannel.Digits = daqInfoSettingsChannel.Digits;
                                    daqInfoChannel.Alias = daqInfoSettingsChannel.Alias;
                                    daqInfoChannel.Color = daqInfoSettingsChannel.Color;
                                    daqInfoChannel.Trigger = daqInfoSettingsChannel.Trigger;
                                }
                            }
                        }
                    }
                    
                    if (daqInfo.Channels != null)
                    {
                        int chIndex = 1;
                        foreach(var ch in daqInfo.Channels)
                        {
                            if(string.IsNullOrEmpty(ch.Alias))
                            {
                                ch.Alias = $"{index}_CH{chIndex}";
                            }
                            chIndex++;
                            if((ch.Color.A | ch.Color.R | ch.Color.G | ch.Color.B) == 0)
                            {
                                ch.Color = new DaqColor(255, 0, 0);
                            }

                            ch.Data = new DaqChannelData();
                        }
                    }
                    Devices.Add(daqInfo);
                }
                index++;
            }
            Status = DaqWorkStatus.Connected;
            RefreshChannels();
        }

        private void RefreshChannels()
        {
            List<DaqChannelInfo> chs = [];
            foreach (var dev in Devices)
            {
                if (dev.Channels == null) continue;
                chs.AddRange(dev.Channels.Where(ch => ch.Status).ToList());
            }
            Channels = [..chs];
            foreach(var ch in Channels)
            {
                if(ch.Alias != null && chartVisibilityDictionary.TryGetValue(ch.Alias, out bool visibility))
                {
                    ch.IsChartVisible = visibility;
                }
                else
                {
                    ch.IsChartVisible = false;
                }
            }
        }

        public async Task CloseDevices()
        {
            foreach (var daq in Devices)
            {
                if (daq.Instance == null)
                {
                    continue;
                }
                try
                {
                    await daq.Instance.CloseAsync(CancellationToken.None);
                }
                catch(Exception ex)
                {
                    Debug.WriteLine($"关闭设备失败:{ex.Message}");
                }
            }
        }

        public async Task<ChannelModel[]?> GetChannelsInfoAsync()
        {
            List<ChannelModel> chs = [];
            //Devices = [];
            foreach (var daq in Daqs)
            {
                var info = await daq.GetChannelsInfoAsync(CancellationToken.None);
                if(info == null)
                {
                    continue;
                }
                chs.AddRange(info);
            }
            return chs.ToArray();
        }

        private CancellationTokenSource? tokenSource;
        protected DaqMeasureData MeasureData { get; set; } = new();
        protected Queue<DaqMeasureData> MeasureDataQueue { get; set; } = new();

        [ObservableProperty]
        private ChartSettingsModel chartSettings = new();

        [ObservableProperty]
        private ObservableCollection<ChannelDetail>? channelDetails;
        [ObservableProperty]
        private long sampleCount;

        [ObservableProperty]
        private ObservableCollection<AlertSettings>? alerts;

        [ObservableProperty]
        private AlertSettings? selectedAlert;

        [ObservableProperty]
        private bool isAlertMute;

        private DaqSettings? daqSettings = new();
        public DaqSettings? DaqSettings
        {
            get => daqSettings;
            set
            {
                SetProperty(ref daqSettings, value);
            }
        }

        //private Settings? settings;
        private readonly PlotService plotService;
        private readonly SettingsService settings;
        private readonly IDialogService dialogService;
        private readonly DataService dataService;
        private readonly ILogger logger;
        public DeviceService(PlotService plotService, SettingsService settings, IDialogService dialogService, DataService dataService, ILogger logger)
        {
            this.plotService = plotService;
            this.settings = settings;
            this.dialogService = dialogService;
            this.dataService = dataService;
            this.logger = logger;
            //WeakReferenceMessenger.Default.Register<ValueChangedMessage<ChartTimeDivision>>(this);
        }

        public void Receive(ValueChangedMessage<ChartTimeDivision> message)
        {
            Debug.WriteLine(message.Value.GetDisplayName());
        }

        [ObservableProperty]
        [NotifyCanExecuteChangedFor(nameof(StartCommand))]
        [NotifyCanExecuteChangedFor(nameof(StopCommand))]
        private DaqWorkStatus status;
        [ObservableProperty]
        private double sampleRate;

        private bool CanStart => Status != DaqWorkStatus.Running;
        private bool CanStop => Status == DaqWorkStatus.Running;


        [ObservableProperty]
        private bool lockYAxes = true;
        public object ChartSync { get; } = new object();

        public async Task GetChannelsAsync(CancellationToken token)
        {
            //await GetChannelsInfoAsync(token);
            var names = DaqSettings.Channels == null ? [] : DaqSettings.Channels.Select(ch => ch.Alias).ToArray();
            bool hasDuplicates = names.Length != names.Distinct().Count();
            //如名字有重复项，再获取一次。
            if (hasDuplicates)
            {
                logger.Error("名称有重复项，再次获取通道信息");
                //await GetChannelsInfoAsync(token);
            }
        }


        private readonly int dataDisplayUpdateIntervalInMillisecond = 200;
        //private DataManagerViewModel? dataManager;
        //private void SaveData(List<string> channelNames, List<int> digits, List<string> units, List<DaqColor> colors)
        //{
        //    List<DaqMeasureData> buffer = [];
        //    DaqMeasureData? data;
        //    buffer.Clear();
        //    dataManager ??= App.Current.Services.GetService(typeof(DataManagerViewModel)) as DataManagerViewModel;
        //    while (DatabaseMeasureDataQueue.TryDequeue(out data))
        //    {
        //        if (data == null) continue;
        //        if (!databaseCreated)
        //        {
        //            dataManager?.CreateDataReport(data.Time, channelNames, digits, units, colors);
        //            databaseCreated = true;
        //        }
        //        buffer.Add(data);
        //        //Debug.WriteLine(data.RawValue.Length);
        //        //Debug.WriteLine(data.RawValue[34]);
        //    }

        //     Debug.WriteLine($"写入数据:{buffer.Count}");
        //    dataManager?.AppendData(buffer);
        //}

        //private bool databaseCreated = false;
        //private async Task DataBaseTask(List<string> channelNames, List<int> digits, List<string> units, List<DaqColor> colors, CancellationToken token)
        //{
        //    Debug.WriteLine("开始数据库任务");
        //    await Task.Run(async () =>
        //    {
        //        DateTime startTime = DateTime.Now;
        //        DateTime now;
        //        List<DaqMeasureData> buffer = [];
        //        TimeSpan timeOutSpan = TimeSpan.FromSeconds(2);
        //        databaseCreated = false;
        //        while (true)
        //        {
        //            now = DateTime.Now;
        //            if (token.IsCancellationRequested)
        //            {
        //                break;
        //            }
        //            if (DatabaseMeasureDataQueue.Count >= 10000 || now - startTime >= timeOutSpan)
        //            {
        //                startTime += timeOutSpan;
        //                SaveData(channelNames, digits, units, colors);
        //            }
        //            await Task.Delay(10);
        //        }
        //        SaveData(channelNames, digits, units, colors);
        //    });
        //    Debug.WriteLine("结束数据库任务");
        //}

        private void PushData(string name, DateTime time, double value)
        {
            var queue = plotQueues.FirstOrDefault(x => x.Name == name);
            if (queue != null)
            {
                queue.DataPoints.Enqueue(new DataPoint
                {
                    Time = time,
                    Value = value
                });
            }
        }

        //private readonly int maxPlotDataCount = 10000;
        private async Task InitPlot(IEnumerable<DaqChannelInfo> channels)
        {
            await plotService.CommandBuffer.Writer.WriteAsync(new PlotMessage
            {
                Type = PlotMessageType.ClearAllSeries,
            });

            DateTime now = DateTime.Now;
            foreach (var ch in channels)
            {
                plotQueues.Add(new PlotBuffer
                {
                    Name = ch.Alias,
                    DataPoints = []
                });

                bool visible;

                await plotService.CommandBuffer.Writer.WriteAsync(new PlotMessage
                {
                    ChannelName = ch.Alias,
                    Type = PlotMessageType.AddSerie,
                    Color = ch.Color.ToScottColor(),
                    IsVisible = ch.IsChartVisible,
                    Unit = ch.Unit
                });
            }
        }

        private List<PlotBuffer> plotQueues = [];
        //private int plotDataCount = 0;

        [ObservableProperty]
        private TimeSpan elapsedTime = TimeSpan.Zero;

        private DateTime firstDateTime = DateTime.Now;

        public async Task ModifyAddress(string address)
        {
            //await CloseAsync(CancellationToken.None);
            //await OpenAsync(address, CancellationToken.None);
        }


        //private bool isTesting = false;
        [RelayCommand]
        private async Task Test()
        {
            await Task.CompletedTask;
        }


        [DllImport("kernel32.dll")]
        private static extern bool Beep(uint dwFreq, uint dwDuration);
        [DllImport("user32.dll")]
        private static extern bool MessageBeep(uint uType);

        private CancellationTokenSource beepTaskCancellationTokenSource = new();
        private bool beepEnabled;
        private async Task BeepTask()
        {
            try
            {
                while (!beepTaskCancellationTokenSource.IsCancellationRequested)
                {
                    if (beepEnabled && !IsAlertMute)
                    {
                        MessageBeep(0xFFFFFFFF);
                        await Task.Delay(1000, beepTaskCancellationTokenSource.Token);
                        //Beep(500, 1000);
                    }
                    await Task.Delay(100, beepTaskCancellationTokenSource.Token);
                }
            }
            catch { }
            beepEnabled = false;
        }

        private void RefreshAlerts(double[] values)
        {
            if (Alerts == null || Alerts.Count == 0)
            {
                return;
            }

            if (Channels.Count != values.Length)
            {
                Debug.WriteLine("显示数据与采集数据的数量不一致");
                return;
            }

            for (int i = 0; i < values.Length; i++)
            {
                var name = Channels[i].Alias;
                var value = values[i];
                foreach (var alert in Alerts)
                {
                    if (alert.IsEnabled && alert.Alias == name)
                    {
                        if ((alert.IsUpperEnabled && value > alert.Upper) || (alert.IsLowerEnabled && value < alert.Lower))
                        {
                            if (!alert.Alerting)
                            {
                                alert.Alerting = true;
                                beepEnabled = true;
                                WeakReferenceMessenger.Default.Send(new DesktopAlertMessage("已触发报警", $"通道[{alert.Alias}] {alert.Detail}"));
                            }
                        }
                    }
                }
            }
        }
        private void ClearAlertsState()
        {
            if (Alerts == null)
            {
                return;
            }
            foreach (var alert in Alerts)
            {
                alert.Alerting = false;
            }
        }

        private TriggerInfo GetTriggerInfo(DaqChannelInfo ch)
        {
            TriggerInfo triggerInfo = new();
            triggerInfo.Logic = ch.Trigger.Logic;
            triggerInfo.Type1 = ch.Trigger.Type1;
            triggerInfo.Type2 = ch.Trigger.Type2;

            triggerInfo.Value1 = (int)(ch.Trigger.Value1 * Math.Pow(10, ch.Digits));
            triggerInfo.Value2 = (int)(ch.Trigger.Value2 * Math.Pow(10, ch.Digits));

            return triggerInfo;
        }


        private async Task DaqTask(CancellationToken token)
        {
            if (Status == DaqWorkStatus.Running) return;
            Status = DaqWorkStatus.Connecting;
            await OpenDevices(settings.Devices);
            foreach(var dev in Devices)
            {
                if (dev.Instance == null) throw new Exception("设备实例为null");
                await dev.Instance.SendDaqSettings(dev, CancellationToken.None);
            }
            if(Channels == null || Channels.Count == 0)
            {
                await CloseDevices();
                throw new Exception("请选择至少一个通道");
            }
            CheckChannelNames();
            SampleCount = 0;
            ElapsedTime = TimeSpan.Zero;
            WeakReferenceMessenger.Default.Send(new ValueChangedMessage<ChartTimeDivision>(new()));

            logger.Information("开始运行");
            
            Status = DaqWorkStatus.Running;
            //int chIndex = 1;
            //int refreshCount = 0;

            //DatabaseMeasureDataQueue.Clear();
            MeasureDataQueue.Clear();

            ClearAlertsState();
            
            await InitPlot(Channels);


            int validChannelsCount = Channels.Count;
            Debug.WriteLine($"有效通道数：{validChannelsCount}");
            //try
            {
                //获取采样率
                logger.Information("获取采样率");
                SampleRate = Devices[0].Instance == null ? 1 : await Devices[0].Instance.GetSampleRateAsync(token);
                logger.Information($"获取成功，采样率为{SampleRate}s");
                dataService.Start((int)(1 / SampleRate), Channels
                .Select(ch => new Daq.Services.ChannelInfo { Digits = ch.Digits, Name = ch.Alias, Unit = ch.Unit, Trigger = GetTriggerInfo(ch) })
                .ToList(), settings.SystemSettings.Instance.DataDirectory, settings.SystemSettings.Instance.Prefix);
                DateTime startTime = DateTime.Now;
                DateTime updateDisplayStartTime = DateTime.Now;

                double[] values = new double[validChannelsCount];
                double[] minValues = new double[validChannelsCount];
                double[] maxValues = new double[validChannelsCount];
                long[] sum = new long[validChannelsCount];
                double[] avg = new double[validChannelsCount];
                double[] ranges = new double[validChannelsCount];

                for (int i = 0; i < validChannelsCount; i++)
                {
                    minValues[i] = double.PositiveInfinity;
                    maxValues[i] = double.NegativeInfinity;
                }

                double value;
                int digits;
                bool firstData = true;
                Random _random = new();
                logger.Information("开始采集");
                long dataCount = 0;
                int groupCount = 1;
                double fetchTime = SampleRate * groupCount;
                DateTime dataStartTime = DateTime.Now;
                bool dataValid;
                while (!token.IsCancellationRequested)
                {
                    DateTime now = DateTime.Now;
                    //fetchTime = SampleRate * groupCount;
                    //Debug.WriteLine("fetch=" + fetchTime);
                    dataValid = false;
                    if (firstData || (now - startTime).TotalSeconds >= fetchTime)
                    {
                        startTime = startTime.AddSeconds(fetchTime);

                        int queueCount = int.MaxValue;
                        //获取一次数据
                        foreach (var daq in Devices)
                        {
                            groupCount = await daq.Instance.FetchAsync(1000, token);
                            if(daq.Instance.MeasureDataQueue.Count < queueCount)
                            {
                                queueCount = daq.Instance.MeasureDataQueue.Count;
                            }
                        }

                        for(int i = 0; i < queueCount; i++)
                        {
                            dataCount++;
                            int index = 0;
                            int[] rawData = new int[validChannelsCount];
                            DateTime? time = null;
                            foreach(var daq in Devices)
                            {
                                var data1 = daq.Instance.MeasureDataQueue.Dequeue();
                                int chIndex = 0;
                                foreach (var ch in daq.Channels)
                                {
                                    if (ch.Alias == "电流2")
                                    {
                                        ;
                                    }
                                    if (!ch.Status) continue;
                                    digits = ch.Digits;
                                    int intValue = data1.RawValue[chIndex++];
                                    value = intValue;
                                    sum[index] += intValue;
                                    avg[index] = Math.Round(sum[index] / dataCount / Math.Pow(10, digits), digits);
                                    values[index] = Math.Round(value / Math.Pow(10, digits), digits);
                                    minValues[index] = values[index] < minValues[index] ? values[index] : minValues[index];
                                    maxValues[index] = values[index] > maxValues[index] ? values[index] : maxValues[index];
                                    ranges[index] = maxValues[index] - minValues[index];

                                    rawData[index] = intValue;
                                    index++;
                                    time = data1.Time;
                                    if (firstData)
                                    {
                                        firstDateTime = data1.Time;
                                        firstData = false;
                                    }
                                }
                                
                            }
                            dataService.AppendData((ulong)dataCount, rawData);
                            

                            RefreshAlerts(values);
                            //Debug.WriteLine(data.RawValue[0]);
                            //PushData(data.Time, values);

                            //Debug.WriteLine($"len:{data.RawValue.Length}");
                            //DatabaseMeasureDataQueue.Enqueue(data);

                            int count = 0;
                            if(time != null)
                            {
                                foreach (var ch in Channels)
                                {
                                    await plotService.DataBuffer.Writer.WriteAsync(new PlotDataMessage
                                    {
                                        ChannelName = ch.Alias,
                                        Value = values[count],
                                        Average = avg[count],
                                        Time = (DateTime)time
                                    });
                                    count++;
                                    //Daq.Plot.DataBuffer.Enqueue(new PlotDataMessage
                                    //{
                                    //    ChannelName = ch.Alias,
                                    //    Value = values[count++],
                                    //    Time = data.Time
                                    //});
                                }
                            }
                            
                        }

                        //dataValid = queueCount > 0;
                        //if (MeasureDataQueue.Count > 0)
                        //{
                        //    while (MeasureDataQueue.Count > 0)
                        //    {
                        //        SampleCount++;
                        //        dataCount++;
                        //        var data = MeasureDataQueue.Dequeue();
                        //        //if (data.RawValue.Length != Channels.Count) continue;
                        //        for (int i = 0; i < data.RawValue.Length; i++)
                        //        {
                        //            digits = Channels[i].Digits;
                        //            value = data.RawValue[i];
                        //            sum[i] += data.RawValue[i];
                        //            avg[i] = Math.Round(sum[i] / dataCount / Math.Pow(10, digits), digits);
                        //            values[i] = Math.Round(value / Math.Pow(10, digits), digits);
                        //            minValues[i] = values[i] < minValues[i] ? values[i] : minValues[i];
                        //            maxValues[i] = values[i] > maxValues[i] ? values[i] : maxValues[i];
                        //            ranges[i] = maxValues[i] - minValues[i];
                        //            //PushData(validChannels[i].Alias, data.Time, values[i]);
                        //        }
                        //        dataService.AppendData((ulong)dataCount, data.RawValue);
                        //        if (firstData)
                        //        {
                        //            firstDateTime = data.Time;
                        //            firstData = false;
                        //        }

                        //        RefreshAlerts(values);
                        //        //Debug.WriteLine(data.RawValue[0]);
                        //        //PushData(data.Time, values);

                        //        //Debug.WriteLine($"len:{data.RawValue.Length}");
                        //        //DatabaseMeasureDataQueue.Enqueue(data);

                        //        int count = 0;
                        //        foreach (var ch in Channels)
                        //        {
                        //            plotService.DataBuffer.Enqueue(new PlotDataMessage
                        //            {
                        //                ChannelName = ch.Alias,
                        //                Value = values[count],
                        //                Average = avg[count],
                        //                Time = data.Time
                        //            });
                        //            count++;
                        //            //Daq.Plot.DataBuffer.Enqueue(new PlotDataMessage
                        //            //{
                        //            //    ChannelName = ch.Alias,
                        //            //    Value = values[count++],
                        //            //    Time = data.Time
                        //            //});
                        //        }
                        //    }
                        //    //Debug.WriteLine((DateTime.Now - dataStartTime).TotalSeconds + ":" + dataCount);
                        //}


                    }
                    if ((now - updateDisplayStartTime).TotalMilliseconds >= dataDisplayUpdateIntervalInMillisecond)
                    {
                        updateDisplayStartTime = now;
                        SampleCount = dataCount;
                        //ChartDataBuffer? chartDataBuffer = null;

                        //refreshCount++;

                        //lock (ChartSync)
                        //{
                        //    //DateTime t1 = DateTime.Now;
                        //    int bufferCount = buffer.Count;
                        //    Debug.WriteLine(bufferCount);
                        //    if (bufferCount > 0)
                        //    {

                        //        if (bufferCount >= 300 && bufferCount < 1000)
                        //        {
                        //            bufferCount = 300;
                        //        }

                        //        while (bufferCount-- > 0)
                        //        {
                        //            chartDataBuffer = PopData();
                        //            if (chartDataBuffer != null)
                        //            {
                        //                for (int i = 0; i < _values.Count(); i++)
                        //                {
                        //                    _values[i].AddLast(new DateTimePoint(chartDataBuffer.Time, chartDataBuffer.Values[i]));
                        //                    while (_values[i].Count > 10000) _values[i].RemoveFirst();
                        //                }
                        //                //Debug.WriteLine("更i性能数据");
                        //            }
                        //        }
                        //        _customAxis.CustomSeparators = GetSeparators(_values[0].First().DateTime, _values[0].Last().DateTime);
                        //    }
                        //    //Debug.WriteLine((DateTime.Now - t1).TotalMilliseconds);
                        //}

                        //for (int i = 0; i < MeasureData.Channels.Count(); i++)
                        //{
                        //    MeasureData.Channels[i].Value = values[i];
                        //}
                        for (int i = 0; i < validChannelsCount; i++)
                        {
                            Channels[i].Data.Value = values[i];
                            Channels[i].Data.Min = minValues[i];
                            Channels[i].Data.Max = maxValues[i];
                            Channels[i].Data.Average = avg[i];
                            Channels[i].Data.Range = ranges[i];
                        }


                        //                  foreach (var group in MeasureChannelGroups)
                        //{
                        //	int index = 0;
                        //	foreach (var ch in group.Channels)
                        //	{
                        //		ch.Value = MeasureData.Channels[index++].Value;
                        //	}
                        //}
                    }
                    if (!firstData)
                    {
                        ElapsedTime = DateTime.Now - firstDateTime;
                    }
                    if (!dataValid)
                    {
                        //await Task.Delay(1, token);
                    }
                }
            }
            //catch (OperationCanceledException)
            //{
            //    Debug.WriteLine("停止采集");
            //    logger.Information("停止采集");
            //}
            //catch (Exception ex)
            //{
            //    string error = $"异常退出：{ex.Message}";
            //    Debug.WriteLine(error);
            //    logger.Error(error);
            //}

            //try
            //{
            //    Debug.WriteLine("关闭设备");
            //    logger.Information("关闭设备");
            //    //await StopAsync(CancellationToken.None);
            //    //await CloseAsync(CancellationToken.None);
            //}
            //catch (Exception ex)
            //{
            //    string error = $"关闭失败：{ex.Message}";
            //    Debug.WriteLine(error);
            //    logger.Information(error);
            //}
            //tokenSource.Cancel();
            //beepTaskCancellationTokenSource.Cancel();
            //dataService?.Stop();
            //await Task.WhenAll([beepTask]);
            //Status = DaqWorkStatus.Disconnected;
        }

        private void ClearBuffer()
        {
            MeasureDataQueue.Clear();
            foreach (var dev in Devices)
            {
                dev.Instance?.MeasureDataQueue.Clear();
            }
              
        }

        [RelayCommand(CanExecute = nameof(CanStart))]
        private async Task Start()
        {
            ClearBuffer();
            if (Status == DaqWorkStatus.Running) return;
            beepTaskCancellationTokenSource = new();
            var beepTask = BeepTask();
            try
            {
                tokenSource = new CancellationTokenSource();
                await DaqTask(tokenSource.Token);
            }
            catch (OperationCanceledException)
            {
                Debug.WriteLine("停止采集");
                logger.Information("停止采集");
            }
            catch (InvalidOperationException ex)
            {
                logger.Information("设备已断开");
                await dialogService.ShowMessageAsync("错误", "设备已断开");
            }
            catch (Exception ex)
            {
                string error = $"异常退出：{ex.Message}";
                Debug.WriteLine(error);
                logger.Error(error);
                await dialogService.ShowMessageAsync("错误", error);
            }

            try
            {
                Debug.WriteLine("关闭设备");
                logger.Information("关闭设备");
                //await StopAsync(CancellationToken.None);
                //await CloseAsync(CancellationToken.None);
            }
            catch (Exception ex)
            {
                string error = $"关闭失败：{ex.Message}";
                Debug.WriteLine(error);
                logger.Information(error);
            }
            tokenSource.Cancel();
            beepTaskCancellationTokenSource.Cancel();
            dataService?.Stop();
            await Task.WhenAll([beepTask]);
            Status = DaqWorkStatus.Disconnected;

            foreach (var dev in Devices)
            {
                if (dev.Instance == null) continue;
                await dev.Instance.CloseAsync(CancellationToken.None);
            }

            Status = DaqWorkStatus.Disconnected;
            return;


            await OpenDevices(settings.Devices);
            var info = await GetChannelsInfoAsync();
            //foreach (var daq in Daqs)
            //{
            //    if (daq.DaqSettings == null) throw new Exception($"未获取到[型号：{daq.Model}]，SN:{daq.SN}]的设备配置");
            //}

            //foreach (var ch in DaqSettings.Channels)
            //{
            //    if (ch.Unit == null || ch.Alias == null)
            //    {
            //        throw new Exception("请检查通道名称和通道单位");
            //    }
            //}

           
        }

        [RelayCommand(CanExecute = nameof(CanStop))]
        private void Stop()
        {
            this.tokenSource?.Cancel();
        }

        [RelayCommand]
        private void ExportChart(object param)
        {
            if (param == null) return;
            string? extName = param.ToString();
            if (string.IsNullOrWhiteSpace(extName)) return;
            var view = App.Current.Services.GetService<DaqView>();
            view?.OpenSaveImageDialog(extName);
        }

        [RelayCommand]
        private async Task AddAlert()
        {
            var view = new AlertSettingsView(Channels);
            var alertSettings = new AlertSettings();
            view.DataContext = alertSettings;
            view.Owner = App.Current.MainWindow;
            view.ShowDialog();
            if (view.DialogResult == true)
            {
                if (Alerts == null)
                {
                    Alerts = [];
                }
                Alerts.Add(alertSettings);
            }
        }

        [RelayCommand]
        private void DeleteAlert()
        {
            if (Alerts == null || SelectedAlert == null)
            {
                return;
            }

            RadWindow.Confirm(new DialogParameters()
            {
                Header = "确认删除",
                Content = $"确定删除[{SelectedAlert.Alias}]的报警吗？",
                Closed = OnConfirmWindowClosed
            });
            if (deleteConfirmResult)
            {
                Alerts.Remove(SelectedAlert);
            }
        }

        private bool deleteConfirmResult;
        private void OnConfirmWindowClosed(object sender, WindowClosedEventArgs e)
        {
            deleteConfirmResult = e.DialogResult == true;
        }

        private async Task<ObservableCollection<DaqInfo>?> GetDevicesInfo()
        {
            return null;
        }

        internal void CheckChannelNames()
        {
            List<string> names = [];
            foreach(var dev in Devices)
            {
                if (dev.Channels == null) continue;
                foreach(var ch in dev.Channels)
                {
                    if (string.IsNullOrWhiteSpace(ch.Alias)) throw new Exception("通道名称不能为空");
                    if (names.Contains(ch.Alias)) throw new Exception($"通道名称[{ch.Alias}]重复");
                    names.Add(ch.Alias);
                }
            }
        }

        internal async Task SaveSettings()
        {
            //await settings.DaqsSettings.Load();
            settings.DaqsSettings.Instance.Daqs ??= [];
            foreach(var dev in Devices)
            {
                var daq = settings.DaqsSettings.Instance.Daqs.FirstOrDefault(daq => daq.SN == dev.SN);
                if (daq == null)
                {
                    while(settings.DaqsSettings.Instance.Daqs.Count > 100)
                    {
                        settings.DaqsSettings.Instance.Daqs.RemoveAt(0);
                    }
                    settings.DaqsSettings.Instance.Daqs.Add(dev);
                }
                else
                {
                    settings.DaqsSettings.Instance.Daqs.Remove(daq);
                    settings.DaqsSettings.Instance.Daqs.Add(dev);
                }
            }
            foreach(var dev in Devices)
            {
                if (dev.Instance == null) continue;
                await dev.Instance.SendDaqSettings(dev, CancellationToken.None);
            }
            RefreshChannels();
            await settings.DaqsSettings.Save();
        }

        public async Task ClearSettings()
        {
            settings.DaqsSettings.Instance = new();
            await settings.DaqsSettings.Save();
        }
    }

    public partial class DaqChannelData : ObservableObject
    {
        private double? _value;
        [JsonIgnore]
        public double? Value
        {
            get => _value;
            set => SetProperty(ref _value, value);
        }

        private double? min;
        [JsonIgnore]
        public double? Min
        {
            get => min;
            set => SetProperty(ref min, value);
        }

        private double? max;
        [JsonIgnore]
        public double? Max
        {
            get => max;
            set => SetProperty(ref max, value);
        }

        private double? average;
        [JsonIgnore]
        public double? Average
        {
            get => average;
            set => SetProperty(ref average, value);
        }

        private double? range;
        [JsonIgnore]
        public double? Range
        {
            get => range;
            set => SetProperty(ref range, value);
        }
    }

    public partial class TriggerSettings : ObservableObject
    {
        [ObservableProperty]
        private TriggerType type1;
        [ObservableProperty]
        private TriggerType type2;
        [ObservableProperty]
        private double value1;
        [ObservableProperty]
        private double value2;
        [ObservableProperty]
        private Logic logic;

        public static List<Logic> Logics => EnumHelper<Logic>.ToList();
        public static List<TriggerType> Types => EnumHelper<TriggerType>.ToList();
        partial void OnLogicChanged(Logic value)
        {
            if(value == Logic.None)
            {
                Type2 = TriggerType.None;
                Value2 = 0;
            }
            OnPropertyChanged(string.Empty);
        }

        //public override string ToString()
        //{
        //    if (Type1 == TriggerType.None) return "";
        //    return "✔";
        //}
    }

    public partial class DaqChannelInfo : ObservableObject
    {
        private string? alias;
        [JsonPropertyName("alias")]
        public string? Alias
        {
            get => alias;
            set => SetProperty(ref alias, value);
        }
        private string? unit;
        [JsonPropertyName("unit")]
        public string? Unit
        {
            get => unit;
            set => SetProperty(ref unit, value);
        }
        private int digits;
        [JsonPropertyName("digits")]
        public int Digits
        {
            get => digits;
            set => SetProperty(ref digits, value);
        }
        private DaqColor color;
        [JsonPropertyName("color")]
        public DaqColor Color
        {
            get => color;
            set => SetProperty(ref color, value);
        }
        private bool status;
        [JsonPropertyName("status")]
        public bool Status
        {
            get => status;
            set => SetProperty(ref status, value);
        }
        private bool isEnabled;
        [JsonPropertyName("isEnabled")]
        public bool IsEnabled
        {
            get => isEnabled;
            set => SetProperty(ref isEnabled, value);
        }

        private bool isChartVisible;
        [JsonIgnore]
        public bool IsChartVisible
        {
            get => isChartVisible;
            set => SetProperty(ref isChartVisible, value);
        }

        //private bool isSelected;
        //[JsonIgnore]
        //public bool IsSelected
        //{
        //    get => isSelected;
        //    set => SetProperty(ref isSelected, value);
        //}

        private TriggerSettings trigger;
        [JsonPropertyName("trigger")]
        public TriggerSettings Trigger
        {
            get => trigger;
            set => SetProperty(ref trigger, value);
        }

        [JsonPropertyName("slotIndex")]
        public int SlotIndex { get; set; } = -1;
        [JsonPropertyName("index")]
        public int Index { get; set; } = -1;

        private DaqChannelData? data;
        [JsonIgnore]
        public DaqChannelData? Data
        {
            get => data;
            set => SetProperty(ref data, value);
        }

        public DaqChannelInfo()
        {
            Trigger = new();
        }
    }
    public partial class DaqInfo : ObservableObject
    {
        private string? model;
        [JsonPropertyName("model")]
        public string? Model
        {
            get => model;
            set => SetProperty(ref model, value);
        }

        private string? address;
        [JsonPropertyName("ip")]
        public string? Address
        {
            get => address;
            set => SetProperty(ref address, value);
        }

        private string? netmask;
        [JsonPropertyName("netmask")]
        public string? Netmask
        {
            get => netmask;
            set => SetProperty(ref netmask, value);
        }

        private string? version;
        [JsonPropertyName("version")]
        public string? Version 
        {
            get => version;
            set => SetProperty(ref version, value);
        }

        private string? sn;
        [JsonPropertyName("sn")]
        public string? SN
        {
            get => sn;
            set => SetProperty(ref sn, value);
        }

        private ObservableCollection<DaqChannelInfo>? channels;
        [JsonPropertyName("channels")]
        public ObservableCollection<DaqChannelInfo>? Channels
        {
            get => channels;
            set => SetProperty(ref channels, value);
        }

        private DaqBase? instance;
        [JsonIgnore]
        public DaqBase? Instance
        {
            get => instance;
            set => SetProperty(ref instance, value);
        }

    }
}
